import ast
import logging
import threading
from datetime import datetime

from app import db, redis_client, redis_ready,set_redis_error
from app.models import House, Address, User
from app.enums.enums import HouseStatusEnum
from app.service.user_service import UserService
from sqlalchemy import or_
from flask import request
from app.util.log_utils import add_log_event

# 配置日志记录器
logger = logging.getLogger(__name__)


def record_ip(client_ip):
    """
    redis记录IP
    :return:
    """
    try:
        if redis_ready:
            # 获取请求IP
            # client_ip = request.remote_addr
            # redis中记录IP
            key = "active_ip:" + str(datetime.now().date())
            redis_client.sadd(key, client_ip)
            redis_client.expire(key, 3600 * 24 * 2)
    except Exception as e:
        logger.error(f"redis异常，无法记录信息: {str(e)}")
        set_redis_error()

def get_data_from_redis(page,size,order):
    """
    从redis中获取数据
    :param order: 排序
    :param page: 分页
    :param size: 页大小
    :return: 获取成功/失败，数据
    """
    try:
        if redis_ready:
            key=f'houses:{page}:{size}:{order}'
            data = redis_client.get(key)
            if data:
                return True,ast.literal_eval(data)
            else:
                return False,None
        return False,None
    except Exception as e:
        logger.error(f"redis异常: {str(e)}")
        set_redis_error()
        return False,None


class HouseService:
    """
    房屋服务类，处理所有房屋相关的业务逻辑
    """

    @staticmethod
    def add_house(args, uid):
        """
        添加新房屋
        Args:
            args: 房屋信息字典
            uid: 房东用户ID
        Returns:
            bool: 是否添加成功
        """
        logger.info(f"开始添加新房屋，房东ID: {uid}")
        try:
            # 创建新地址
            new_address = Address(
                city=args['city'],
                district=args['district'],
                detailed_address=args['detailed_address']
            )
            db.session.add(new_address)
            db.session.flush()
            logger.info(f"创建新地址成功，地址ID: {new_address.id}")

            # 创建新房屋
            new_house = House(
                title=args['title'],
                price=args['price'],
                house_type=args['houseType'],
                area=args['area'],
                address_id=new_address.id,
                landlord_id=uid,
                img_urls=str(HouseService.list_without_none(args['images'])),
                descriptor=str(HouseService.list_without_none(args['keywords'])),
                deposit=args['deposit'],
                status=HouseStatusEnum.CHECKING.value
            )
            # 添加入数据库
            db.session.add(new_house)
            db.session.commit()
            logger.info(f"房屋添加成功，房屋ID: {new_house.id}")
            return True
        except Exception as e:
            # 发生错误，回滚
            db.session.rollback()
            logger.error(f"添加房屋失败: {str(e)}, 房东ID: {uid}")
            add_log_event("添加房屋失败", f"房东{uid}添加房屋失败: {str(e)}")
            return False

    @staticmethod
    def delete_house(uid, house_id):
        """
        删除房屋
        Args:
            uid: 房东用户ID
            house_id: 房屋ID
        Returns:
            bool: 是否删除成功
        """
        logger.info(f"开始删除房屋，房屋ID: {house_id}, 房东ID: {uid}")
        house = House.query.filter_by(id=house_id, landlord_id=uid).first()
        if house is None:
            logger.warning(f"删除房屋失败: 房屋不存在或无权操作，房屋ID: {house_id}, 房东ID: {uid}")
            return False
        address = Address.query.filter_by(id=house.address_id).first()
        try:
            # 删除操作
            db.session.delete(house)
            db.session.delete(address)  # 删除关联的地址
            db.session.commit()
            logger.info(f"房屋删除成功，房屋ID: {house_id}")
            return True
        except Exception as e:
            # 发生错误，回滚
            db.session.rollback()
            logger.error(f"删除房屋失败: {str(e)}, 房屋ID: {house_id}")
            add_log_event("删除房屋出现错误", f"房东{uid}删除房屋{house_id}失败: {str(e)}")
            return False

    @staticmethod
    def get_house_info(house, address, landlord):
        """
        获取房屋基本信息
        Args:
            house: 房屋对象
            address: 地址对象
            landlord: 房东用户对象
        Returns:
            dict: 房屋信息字典
        """
        return {
            'id': house.id,
            'title': house.title,
            'price': house.price,
            'houseType': house.house_type,
            'area': house.area,
            'address': {
                'city': address.city,
                'district': address.district,
                'detailed_address': address.detailed_address
            },
            'landlord': {
                'id': landlord.id,
                'username': landlord.username,
                'avatar': landlord.avatar,
                'age': landlord.age,
                'gender': landlord.gender,
                'phone': landlord.phone,
                'email': landlord.email
            },
            'images': ast.literal_eval(house.img_urls),
            'keywords': ast.literal_eval(house.descriptor),
            'deposit': house.deposit,
            'status': house.status,
            'create_time': str(house.create_time)
        }

    @staticmethod
    def get_house_list(args):
        """
        获取房屋列表
        Args:
            args: 查询参数字典
        Returns:
            list: 房屋列表
        """
        client_ip = request.remote_addr
        threading.Thread(target=record_ip, args=(client_ip,)).start()
        logger.info(f"开始获取房屋列表，查询参数: {args}")
        # 获取分页信息
        page = int(args.get('page', 1))
        size = int(args.get('size', 12))
        order = int(args.get('order', 0))
        title = args.get('title', '')
        status = int(args.get('status', HouseStatusEnum.AVAILABLE.value))
        landlord_name = args.get('landlordName', '')
        # 查询处理
        query = House.query
        # 排序处理
        if order == 1:
            query = query.order_by(House.price.desc())
        elif order == 2:
            query = query.order_by(House.price.asc())
        elif order == 3:
            query = query.order_by(House.area.desc())

        # 标题模糊匹配
        if title:
            query = query.filter(House.title.like(f'%{title}%'))
        # 状态过滤
        if status != HouseStatusEnum.ALL.value:
            query = query.filter_by(status=status)
        # 房东姓名模糊匹配
        if landlord_name:
            user = User.query.filter(User.username.like(f'%{landlord_name}%')).first()
            if user:
                query = query.filter_by(landlord_id=user.id)
            else:
                return {
                    'total': 0,
                    'list': []
                }
        need_in_redis=False
        if not title and not landlord_name:
            success,data = get_data_from_redis(page, size, order)
            if success:
                total = House.query.count()
                logger.info("直接从redis中返回数据")
                return {
                    'total': total,
                    'list': data
                }
            need_in_redis = True
        # 获取分页房屋数据
        paginated_houses = query.paginate(page=page, per_page=size, error_out=False)
        # 构建最终数据
        houses = []
        for house in paginated_houses.items:
            address = Address.query.filter_by(id=house.address_id).first()
            landlord = User.query.filter_by(id=house.landlord_id).first()
            houses.append(HouseService.get_house_info(house, address, landlord))

        logger.info(f"成功获取房屋列表，数量: {len(houses)}")
        if need_in_redis and redis_ready:
            redis_client.setex(f"houses:{page}:{size}:{order}",60*60, str(houses)) # 1小时过期
        return {
            'total': paginated_houses.total,
            'list': houses
        }

    @staticmethod
    def get_house_by_landlord(uid):
        """
        获取房东发布的房屋列表
        Args:
            uid: 房东用户ID
        Returns:
            list: 房屋列表
        """
        logger.info(f"开始获取房东发布的房屋列表，房东ID: {uid}")
        houses = House.query.filter_by(landlord_id=uid).all()
        res = []
        for house in houses:
            address = Address.query.filter_by(id=house.address_id).first()
            res.append({
                'id': house.id,
                'title': house.title,
                'price': house.price,
                'deposit': house.deposit,
                'rooms': house.house_type.split('室')[0],
                'halls': house.house_type.split('室')[1].split('厅')[0],
                'area': house.area,
                'city': address.city,
                'district': address.district,
                'detailed_address': address.detailed_address,
                'images': ast.literal_eval(house.img_urls),
                'keywords': ast.literal_eval(house.descriptor),
                'createdAt': str(house.create_time),
                'updatedAt': str(house.update_time),
                'status': house.status
            })
        logger.info(f"成功获取房东发布的房屋列表，数量: {len(res)}, 房东ID: {uid}")
        return res

    @staticmethod
    def update_house(update_house_data, uid):
        """
        更新房屋信息
        Args:
            update_house_data: 更新数据字典
            uid: 房东用户ID
        Returns:
            bool: 是否更新成功
        """
        logger.info(f"开始更新房屋信息，房屋ID: {update_house_data['id']}, 房东ID: {uid}")
        try:
            house = House.query.filter_by(id=update_house_data['id'], landlord_id=uid).first()
            if house is None:
                logger.warning(f"更新房屋失败: 房屋不存在或无权操作，房屋ID: {update_house_data['id']}")
                return False
            # 更新房屋信息
            house.title = update_house_data['title']
            house.price = update_house_data['price']
            house.house_type = update_house_data['houseType']
            house.area = update_house_data['area']
            house.img_urls = str(HouseService.list_without_none(update_house_data['images']))
            house.descriptor = str(HouseService.list_without_none(update_house_data['keywords']))
            house.deposit = update_house_data['deposit']
            # 更新对应地址信息
            address = Address.query.filter_by(id=house.address_id).first()
            address.city = update_house_data['city']
            address.district = update_house_data['district']
            address.detailed_address = update_house_data['detailed_address']
            # 提交更改
            db.session.commit()
            logger.info(f"房屋信息更新成功，房屋ID: {update_house_data['id']}")
            return True
        except Exception as e:
            # 错误回滚
            db.session.rollback()
            logger.error(f"更新房屋失败: {str(e)}, 房屋ID: {update_house_data['id']}")
            return False

    @staticmethod
    def update_house_status(data, uid):
        """
        更新房屋状态
        Args:
            data: 更新数据字典
            uid: 房东用户ID
        Returns:
            bool: 是否更新成功
        """
        logger.info(f"开始更新房屋状态，房屋ID: {data['id']}, 房东ID: {uid}")
        try:
            status = data['status']
            house_id = data['id']
            is_admin = UserService.check_admin(uid)  # 判断是否为管理员
            house = House.query.filter_by(id=house_id, landlord_id=uid).first() \
                if not is_admin \
                else House.query.filter_by(id=house_id).first()
            # 判断房屋是否存在
            if house is None:
                logger.warning(f"更新房屋状态失败: 房屋不存在或无权操作，房屋ID: {data['id']}")
                return False
            # 更新状态
            if is_admin and status in [HouseStatusEnum.CHECK_FAIL.value, HouseStatusEnum.AVAILABLE.value,
                                       HouseStatusEnum.ERROR.value] or not is_admin and status in [
                HouseStatusEnum.REPAIRING.value, HouseStatusEnum.AVAILABLE.value, HouseStatusEnum.CHECKING.value]:
                house.status = status
                db.session.commit()
                logger.info(f"房屋状态更新成功，房屋ID: {data['id']}, 新状态: {data['status']}")
                return True
            logger.warning(f"更新房屋状态失败: 无权操作，房屋ID: {data['id']}, 新状态: {data['status']}")
            return False
        except Exception as e:
            db.session.rollback()
            logger.error(f"更新房屋状态失败: {str(e)}, 房屋ID: {data['id']}")
            return False

    @staticmethod
    def list_without_none(data):
        """
        去除列表中的None值
        Args:
            data: 原始列表
        Returns:
            list: 去除None值后的列表
        """
        return [item for item in data if item is not None]

    @staticmethod
    def get_search_result(arg):
        """
        根据特定搜索字段筛选房源，将房源返回前端
        :param data:
        :return:
        """
        # 创建一个 SQLAlchemy 查询对象，用于后续链式添加过滤条件
        # query = House.query
        # query = db.session.query(House)
        # 初始化查询并连接必要的表
        query = db.session.query(House).join(
            Address, House.address_id == Address.id
        ).join(
            User, House.landlord_id == User.id
        )
        # 获取筛选条件
        logger.info("进入搜索，筛选对应房屋列表")
        # 提取参数（添加分页参数）
        page = int(arg.get('page', 1))
        size = int(arg.get('size', 12))
        order = int(arg.get('order', 0))
        keyword = arg.get('keyword', '').strip()
        house_type_code = arg.get('houseType')
        rent_type = arg.get('rentType')
        region = arg.get('region', 'all')
        min_price_str = arg.get('minPrice')
        max_price_str = arg.get('maxPrice')
        # 将价格参数从字符串转换为整数，如果无法转换则设为 None
        try:
            min_price = int(min_price_str) if min_price_str else None
        except ValueError:
            min_price = None

        try:
            max_price = int(max_price_str) if max_price_str else None
        except ValueError:
            max_price = None
        # 筛选逻辑
        if keyword:
            query = query.filter(or_(
                House.title.like(f'%{keyword}%'),
                House.descriptor.like(f'%{keyword}%'),
                Address.district.like(f'%{keyword}%'),
                Address.detailed_address.like(f'%{keyword}%')
            ))

        # 处理房屋类型数据转换
        # 定义 house_type 代码到字符串的映射
        house_type_mapping = {
            '11': '1室1厅',
            '21': '2室1厅',
            '22': '2室2厅',
            '31': '3室1厅',
            '32': '3室2厅'
        }
        # 将 house_type 代码转换为对应的字符串
        house_type = house_type_mapping.get(house_type_code)
        if house_type:
            # query = query.filter(House.house_type.like(f'%{house_type}%'))
            query = query.filter(House.house_type == house_type)
        if rent_type:
            query = query.filter(House.descriptor.like(f'%{rent_type}%'))
        # 查询城市
        if region:
            logger.info(f"查询城市")
            query = query.filter(Address.city.like(f'%{region}%'))
        # 价格范围筛选
        if min_price is not None and min_price > 0:
            query = query.filter(House.price >= min_price)
        if max_price is not None and max_price > 0:
            query = query.filter(House.price <= max_price)
        logger.info(f"执行查询，条件: {query}")  # 打印SQL查询语句
        logger.info(
            f"参数状态: keyword={keyword}, house_type={house_type}, "
            f"rent_type={rent_type}, region={region}, min_price={min_price}, max_price={max_price}")

        # 排序处理
        if order == 1:
            query = query.order_by(House.price.desc())
        elif order == 2:
            query = query.order_by(House.price.asc())
        elif order == 3:
            query = query.order_by(House.area.desc())

            # 分页查询
        paginated_houses = query.paginate(page=page, per_page=size, error_out=False)
        temphouses = paginated_houses.items

        # 最终组装houses
        houses = []
        for house in temphouses:
            address = Address.query.filter_by(id=house.address_id).first()
            landlord = User.query.filter_by(id=house.landlord_id).first()
            houses.append(HouseService.get_house_info(house, address, landlord))

        if not houses:  # 如果没有找到符合条件的房屋
            logger.info(f"未找到符合条件的房屋，参数: {arg}")
            return {
                'list': []
            }  # 返回空列表或自定义空结果（如错误提示）

        logger.info(f"成功获取房屋列表，数量: {len(houses)}")
        return {
            'list': houses
        }  # 返回符合条件的房屋列表
